# import os
# import sys
# sys.path.append(os.getcwd())

from network_form.utils_downstream import close_top_k, history_response2
from utils import *
import networkx as nx

class IModel:
    def __init__(self) -> None:
        pass
    # 预测结果返回值
    # yes   : 1
    # no    : 0
    # maybe : 0.5
    def predict(self, event, person):
        pass

    def __call__(self, event:dict, person:dict):
        return self.predict(event, person)

class CountryModel(IModel):
    """
    如果不在一个国家那么就拒绝,
    如果没有属性country, 那么就返回True
    """
    def __init__(self) -> None:
        super().__init__()
    def predict(self, event: dict, person:dict):
        if event['country']!='' and person['country']!='' and (event['has_venue']==True):
            return 1 if event['country'] == person['country'] else 0
        return 1

class LonLatModel(IModel):

    def __init__(self, measure = LonLatDiffMeasure(lat_threshold=30,lon_threshold=60)) -> None:
        super().__init__()
        self.measure = measure

    """
    根据所在城市经纬度判断
    """
    def predict(self, event:dict, person:dict):
        magic_number = 114115.
        if ("latitude" in event) and ("latitude" in person) and ("longitude" in event) and ("longitude" in person):
            if event['latitude'] != magic_number and event['longitude'] != magic_number and person['latitude'] != magic_number and person['longitude'] != magic_number :
                return 1 if self.measure(event['longitude'], event['latitude'], person['longitude'], person['latitude']) else 0
        return 1

# class HistoryModel(IModel):
#     # event_list 应该不包含测试用的event_list
#     def __init__(self, event_list, member_list, group_list, topic_list) -> None:
#         super().__init__()
#         groups = dict()
#         events = dict()
#         members = dict()
#         topics = dict()
#         for group in group_list:
#             groups[str(group['id'])] = group
#         for event in event_list:
#             # topic = groups[event['group_id']]['topics']
#             # event['topics'] = topic
#             events[str(event['id'])] = event
#         for topic in topic_list:
#             topics[str(topic['id'])] = topic
#         for mem in member_list:
#             mem['event response'] = dict()
#             members[str(mem['id'])] = mem
#         for event in events:
#             mrs = event['member and response']
#             for m_id in mrs:
#                 members[m_id]['event response'][event['id']]=mrs[m_id]

#         self.groups = groups
#         self.events = events
#         self.topics = topics
#         self.members = members

#     # 返回member收到的event邀请时间最近的k个
#     def history_event_response(self, member_id, k):
#         events = self.members[member_id]['event response']
#         events = sorted(events, key= lambda i:i['created_time'])
#         if len(events) < k:
#             return events
#         else:
#             return events[-k:-1]

#     # event应该不包含在event_list里
#     def predict(self, event, member):
#         event_id = event['id']
#         member_id = member['id']
#         return True

class HistoryModel(IModel):
    def __init__(self, all_graph, event_list, group_list, member_list, topic_similarity = TopicSimilarity()) -> None:
        super().__init__()
        self.all_graph = all_graph
        self.group_list = group_list
        self.topic_sim = topic_similarity
        self.member_list = member_list
        self.event_list = event_list

    def predict(self, event: dict, person: dict):
        event_id = event['id']
        member_id = person['id']
        history_list = history_response2(self.all_graph, self.event_list, self.group_list, self.member_list, event_id, member_id)

        # 没有历史参与的活动
        if len(history_list)==0:
            return 0

        # topic相似度?
        member_topics = person['topics']

        max_sim = 0
        max_index = 0

        for index, history_event in enumerate(history_list):
            topics = history_event['topics']
            sim = self.topic_sim(topics, member_topics)

            if sim > max_sim:
                max_sim = sim
                max_index = index
            
        response:str = history_list[max_index]['response']

        if response == 'yes':
            return 1
        elif response == 'no':
            return 0
        else:
            return 0.5

# 组内最相近的k1个人，他们对最相似的k2个事件的回应
# 需要对event_list进行划分
class ClosestMemberModel(IModel):
    # 注意：event_list应当不包含要预测的event
    def __init__(self, event_list, member_list, group_list, k1=5, k2=5, weight1=0.3, weight2=0.7, topic_sim = TopicSimilarity() ) -> None:
        super().__init__()
        self.k1 = k1
        self.k2 = k2
        self.weight1= weight1
        self.weight2 = weight2
        member_dict = dict()
        group_dict = dict()
        event_dict = dict()
        
        for m in member_list:
            m['joined events'] = [] 
            member_dict[str(m['id'])] = m
        for g in group_list:
            group_dict[str(g['id'])] = g
        for e in event_list:
            e_id = str(e['id'])
            event_dict[e_id] = e
            mr = e['member and response']
            for m_id in mr:
                if m_id in member_dict:
                    m_dict = member_dict[m_id]
                    j_dict = {
                            'id': '',
                            'response': '',
                            'topics': []
                        }
                    j_dict['id'] = e_id
                    j_dict['response'] = mr[m_id]
                    j_dict['topics'] = group_dict[e['group_id']]['topics']
                    m_dict['joined events'].append(j_dict)

        self.member_dict = member_dict
        self.group_dict = group_dict
        self.event_dict = event_dict
        self.topic_sim = topic_sim

    def predict(self, event: dict, person: dict):
        event_id = event['id']
        member_id = person['id']

        # 最相近的k1个人
        k1 = self.k1
        # 最相近的k2个事件
        k2 = self.k2
        weight1 = self.weight1 / (self.weight1 + self.weight2)
        weight2 = self.weight2 / (self.weight1 + self.weight2)

        group_members_temp = event['member and response']
        # 组内没有人？
        if len(group_members_temp) == 0:
            return 0.5

        group_members = []
        my_topics = person['topics']
        my_topics = my_topics if my_topics != None else []

        for index, x in enumerate(group_members_temp):
            idx = str(x)
            my_idx = member_id
            if (idx != my_idx):
                mb_dict = self.member_dict[idx]
                mb_dict['topic_sim'] = self.topic_sim(my_topics, mb_dict['topics'])
                group_members.append(self.member_dict[idx])
        # 实际上有很多人的topics列表为[] 空
        # 感觉这个预测出来的结果并不准确
        sorted(group_members, key=lambda x : x['topic_sim'], reverse=True)

        if len(group_members) > k1:
            group_members = group_members[0:k1]

        # 他们参加过的事件
        def new_info():
            return {
                'member id': '',
                'event id': '',
                'sim': 0.,
                'response': 'no'
            }

        response_list = []
        for member in group_members:
            sim1 = member['topic_sim']
            joined_events = member['joined events']
            for joined_event in joined_events:
                joined_event['sim2'] = self.topic_sim(my_topics, joined_event['topics'])
            sorted(joined_events, key=lambda x:x['sim2'], reverse=True)
            if len(joined_events) > k2:
                joined_events = joined_events[0:k2]
            for j in joined_events:
                info = new_info()
                info['member id'] = member_id
                info['event id'] =j['id']
                info['response'] = j['response']
                info['sim'] = weight1*sim1+weight2*j['sim2']
                response_list.append(info)
        sorted(response_list, key=lambda x:x['sim'], reverse=True)

        # 没有历史回应就0.5(maybe)
        if len(response_list)==0:
            return 0.5
        
        yes_num = 0
        no_num = 0
        maybe_num=0

        for response_info in response_list:
            response = response_info['response']

            if response=='yes':
                yes_num+=1
            elif response=='no':
                no_num+=1
            else :
                maybe_num+=1

        max_num = max(yes_num, no_num, maybe_num)

        if max_num==yes_num:
            return 1
        elif max_num==no_num:
            return 0
        else:
            return .5

# 根据它回应事件的yes倾向确定(经常回复yes那么就yes)
# 需要对event_list进行划分
class YesTendencyModel(IModel):
    def __init__(self, event_list, member_list, k=5) -> None:
        super().__init__()
        member_dict = dict()
        self.k=k
        
        for m in member_list:
            m['joined events'] = [] 
            member_dict[str(m['id'])] = m
        for e in event_list:
            e_id = str(e['id'])
            mr = e['member and response']
            for m_id in mr:
                if m_id in member_dict:
                    m_dict = member_dict[m_id]
                    j_dict = {
                            'id': '',
                            'response': '',
                            'topics': [],
                            'time': 0
                        }
                    j_dict['id'] = e_id
                    j_dict['response'] = mr[m_id]
                    j_dict['time'] = e['created_time']
                    m_dict['joined events'].append(j_dict)
        
        self.member_dict=member_dict
    
    def predict(self, event, person):
        member_id = person['id']
        joined_events = self.member_dict[member_id]['joined events']

        sorted(joined_events, key=lambda x:x['time'], reverse=True)

        if len(joined_events)==0:
            return 0.5

        yes_num = 0
        no_num = 0
        maybe_num = 0
        k = self.k if self.k<=len(joined_events) else len(joined_events)
        for i in range(k):
            je = joined_events[i]
            response = je['response']
            if response=='yes':
                yes_num+=1
            elif response=='no':
                no_num+=1
            else:
                maybe_num+=1

        num = max(yes_num, no_num, maybe_num)

        if num==yes_num:
            return 1
        elif num==no_num:
            return 0
        else:
            return 0.5

class OtherMemberModel(IModel):
    def __init__(self, graphs, group_list,k=10) -> None:
        super().__init__()
        self.graphs = graphs
        self.group_list=group_list
        self.k=k

    def predict(self, event, person):
        event_id = str(event['id'])
        member_id = str(person['id'])

        response_list = close_top_k(self.graphs, self.group_list, event_id, member_id, k=self.k)

        yes_num = 0
        no_num = 0
        maybe_num=0

        for response_info in response_list:
            response = response_info['response']

            if response=='yes':
                yes_num+=1
            elif response=='no':
                no_num+=1
            else :
                maybe_num+=1

        max_num = max(yes_num, no_num, maybe_num)

        if max_num==yes_num:
            return 1
        elif max_num==no_num:
            return 0
        else:
            return .5    




    
